package com.ai.util;

import cn.hutool.core.io.file.FileNameUtil;
import com.jcraft.jsch.*;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;
import org.apache.velocity.shaded.commons.io.FilenameUtils;

import java.io.*;
import java.nio.file.Files;

/**
 * @Author jiaok
 * @Date 2024-05-14 16:18
 */
@Slf4j
@Data
@Getter
@Setter
@Accessors(chain = true)
public class SftpFileUploaderUtil {

    /**
     * 目标主机host
     */
    private String host;
    /**
     * 22端口
     */
    private int port = 22;

    /**
     * 登录用户名
     */
    private String username;

    /**
     * 登陆密码
     */
    private String password;

    /**
     * 远程文件地址路径
     */
    private String remoteDirectory;

    public SftpFileUploaderUtil() {
    }

    public SftpFileUploaderUtil(String host, String username, String password, String remoteDirectory) {
        this.host = host;
        this.username = username;
        this.password = password;
        this.remoteDirectory = remoteDirectory;
    }

    /**
     * 文件上传
     * @param localFilePath
     */
    public  String uploadFile(String localFilePath) {
        JSch jsch = new JSch();
        Session session = null;
        ChannelSftp channelSftp = null;
        ChannelExec channelExec = null;

        String command = null;
        try {
            // 创建SSH会话
            session = jsch.getSession(username, host, port);
            session.setPassword(password);
            session.setConfig("StrictHostKeyChecking", "no");
            session.connect();

            // 打开SFTP通道
            channelSftp = (ChannelSftp) session.openChannel("sftp");
            channelSftp.connect();
            log.info("===========================  服务器：{}  SSH链接已建立  ===========================",this.host);


            // 获取本地文件信息
            File localFile = new File(localFilePath);
            String remoteFileName = localFile.getName();
            log.info("===========================  文件传输中......  ===========================");
            // 确保远程目录存在
            ensureRemoteDirectoryExists(channelSftp, remoteDirectory);

            // 切换到远程目录并上传文件
            channelSftp.cd(remoteDirectory);
            channelSftp.put(Files.newInputStream(localFile.toPath()), remoteFileName);
            Thread.sleep(1000);
            log.info("===========================  文件上传成功  ===========================");
            //执行解压命令
            String realName = FileNameUtil.getPrefix(remoteFileName);
            String extension = FilenameUtils.getExtension(remoteFileName);
            if ("zip".equals(extension)) {
                command =  " unzip " + remoteDirectory + "/" + remoteFileName  + " -d " + remoteDirectory  ;
            }else {
                command =  " tar -zxvf " + remoteDirectory + "/" + remoteFileName  + " -C " + remoteDirectory +"/" ;
            }
            log.info("===========================  执行命令：{}  ===========================",command);
            channelExec = (ChannelExec) session.openChannel("exec");
            channelExec.setCommand(command);
            channelExec.connect();

            // 读取命令输出
            BufferedReader reader = new BufferedReader(new InputStreamReader(channelExec.getInputStream()));
            String line;
            while ((line = reader.readLine()) != null) {
                log.info("=========================== remote ssh console :{} ===========================", line);
            }
            // 读取错误流
//            InputStream errorStream = channelExec.getErrStream();
//            BufferedReader errorReader = new BufferedReader(new InputStreamReader(errorStream));
//            while ((line = errorReader.readLine()) != null) {
//                log.error("=========================== remote ssh error :{} ===========================", line);
//            }
            // 等待命令执行完成
//            int exitStatus = channelExec.getExitStatus();
//            log.warn("=========================== Exit status:{} ===========================", exitStatus);
//            InputStream in = channelExec.getInputStream();
//            byte[] tmp = new byte[1024];
//            while (true) {
//                while (in.available() > 0) {
//                    int i = in.read(tmp, 0, 1024);
//                    if (i < 0) {
//                        break;
//                    }
//                    log.info("=========================== remote ssh console :{}  ===========================",new String(tmp, 0, i));
//                }
//
//                if (channelExec.isClosed()) {
//                    // 如果通道已关闭，并且输入流中没有更多数据，则退出循环
//                    if (in.available() == 0) {
//                        log.warn("===========================  Exit status:{}  ===========================",channelExec.getExitStatus());
//                        break;
//                    }
//                }
//                // 如果没有数据可读，则稍微等待一下（避免紧循环）
//                Thread.sleep(1000);
//            }

            //启停文件存储位置
            return remoteDirectory+"/"+realName;
        } catch (JSchException | SftpException | IOException | InterruptedException e) {
            e.printStackTrace();
            log.info("===========================  文件上传失败 ：{} ===========================",e.getMessage());
        } finally {
            if (channelExec != null){
                channelExec.disconnect();
            }
            // 断开SFTP通道和SSH会话
            if (channelSftp != null) {
                channelSftp.disconnect();
            }
            if (session != null) {
                session.disconnect();
            }
        }
        return  null;
    }

    /**
     * 执行解压命令
     * @param command 解压命令
     */
    private void execSSHExtractCommand( String command) {
        log.info("===========================  执行解压命令  ===========================");
        JSch jsch = new JSch();
        Session session = null;
        ChannelSftp channelSftp = null;
        Channel  channel =null;
        try {
            // 创建SSH会话
            session = jsch.getSession(username, host, port);
            session.setPassword(password);
            session.setConfig("StrictHostKeyChecking", "no");
            session.connect();

            // 打开SFTP通道
            channel = session.openChannel("exec");
          ((ChannelExec) channel).setCommand(command);
            channel.connect();
            log.info("===========================  channel连接已建立  ===========================");
            // 读取命令输出
            InputStream in = channel.getInputStream();
            byte[] tmp = new byte[1024];
            while (true) {
                while (in.available() > 0) {
                    int i = in.read(tmp, 0, 1024);
                    if (i < 0) {
                        break;
                    }
                    log.info("=========================== remote ssh console :{}  ===========================",new String(tmp, 0, i));
                }

                if (channel.isClosed()) {
                    // 如果通道已关闭，并且输入流中没有更多数据，则退出循环
                    if (in.available() == 0) {
                        log.warn("===========================  Exit status:{}  ===========================",channel.getExitStatus());
                        break;
                    }
                }
                // 如果没有数据可读，则稍微等待一下（避免紧循环）
                Thread.sleep(1000);
            }

        } catch (JSchException | IOException | InterruptedException e) {
            log.error("=========================== 执行ssh命令报错：{}  ===========================",e.getMessage());
            throw new RuntimeException(e);
        }finally {
            assert channel != null;
            channel.disconnect();
            assert session != null;
            session.disconnect();
        }

    }

    private void ensureRemoteDirectoryExists(ChannelSftp sftpChannel, String remoteDir) throws SftpException {
        String[] dirs = remoteDir.split("/");
        StringBuilder currentDir = new StringBuilder();

        for (String dir : dirs) {
            if (dir.length() > 0) {
                currentDir.append("/").append(dir);
                try {
                    sftpChannel.cd(currentDir.toString());
                } catch (SftpException e) {
                    log.warn("===========================  远程服务器创建文件夹：{}  ===========================",dir);
                    sftpChannel.mkdir(currentDir.toString());
                    sftpChannel.cd(currentDir.toString());
                }
            }
        }
    }

    public static void main(String[] args) {
        // 远程服务器连接参数
        String host = "192.168.8.192";
        int port = 22;
        String username = "server";
        String password = "123456";
        String remoteDirectory = "/home/jiaokang/server/jk";

        // 本地文件路径
        String localFilePath = "D:\\package_test\\epoch_200.pth";

        // 创建上传器对象并调用上传方法
        SftpFileUploaderUtil uploader = new SftpFileUploaderUtil(host, username, password, remoteDirectory);
//        uploader.uploadFile(localFilePath);
        String command ="env && tar -zxvf /home/server/jk/6606/1.0.4/apache-tomcat-9.0.58.tar.gz -C /home/server/jk/6606/1.0.4/";
        uploader.execSSHExtractCommand(command);
    }

}
